package cn.yqn.service.impl;

import cn.yqn.constants.RedisRegistConstant;
import cn.yqn.domain.*;
import cn.yqn.dto.PhoneRegisterDto;
import cn.yqn.dto.RedisRegisterDto;
import cn.yqn.enums.GlobalEnumCode;
import cn.yqn.feign.UaaFeignService;
import cn.yqn.mapper.UserMapper;
import cn.yqn.result.JSONResult;
import cn.yqn.service.IUserAccountService;
import cn.yqn.service.IUserBaseInfoService;
import cn.yqn.service.IUserGrowLogService;
import cn.yqn.service.IUserService;
import cn.yqn.util.AssertUtil;
import cn.yqn.util.BitStatesUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private UaaFeignService uaaFeignService;

    @Autowired
    private IUserAccountService userAccountService;

    @Autowired
    private IUserBaseInfoService userBaseInfoService;

    @Override
    @GlobalTransactional // 代替了 @Transactional
    public void register(PhoneRegisterDto phoneRegisterDto) {
        String mobile = phoneRegisterDto.getMobile();
        Integer regChannel = phoneRegisterDto.getRegChannel();
        String password = phoneRegisterDto.getPassword();
        String smsCode = phoneRegisterDto.getSmsCode();
        // JSR303
        // 手机验证码，判断是否存在，判断是否正确.
        String key = String.format(RedisRegistConstant.PHONE_REGISTER_PREFIX, mobile);
        System.out.println(key);
        Object codeTmp = redisTemplate.opsForValue().get(key);
        System.out.println(codeTmp);
        // 判断验证码是否存在
        AssertUtil.isNotNull(codeTmp, GlobalEnumCode.CODE_EXPIRED_ERROR);
        RedisRegisterDto code = (RedisRegisterDto) codeTmp;
        // 判断是否相等，不相等抛异常
        AssertUtil.isEqualsIgnoreCase(code.getCode(), smsCode, GlobalEnumCode.CODE_INCORRECT_ERROR);
        // 判断手机号是否已被注册
        User user = selectByPhone(mobile);
        AssertUtil.isNull(user, GlobalEnumCode.USER_EXISTED_ERROR);

        // 保存信息
        Login login = new Login();
        login.setUsername(mobile);
        login.setPassword(password);
        login.setType(1);
        login.setEnabled(true);
        JSONResult jsonResult = uaaFeignService.saveOrUpdate(login);
        // 判断是否响应的是熔断数据
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobalEnumCode.ERROR);
        // 我们使用方法进行转换，防止强转报错
        Long loginId = Long.valueOf(jsonResult.getData().toString());
        AssertUtil.isNotNull(loginId, GlobalEnumCode.USER_REGISTER_ERROR);
        // 保存user
        User saveUser = saveUser(loginId, mobile);
        Long userId = saveUser.getId();
        AssertUtil.isNotNull(userId, GlobalEnumCode.USER_REGISTER_ERROR);
        // 保存UserAccount相关表
        UserAccount userAccount = new UserAccount();
        userAccount.setId(userId);
        userAccount.setCreateTime(new Date().getTime());
        userAccountService.insert(userAccount);
        // 保存UserBaseInfo相关表
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setRegChannel(regChannel);
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfo.setId(userId);
        userBaseInfoService.insert(userBaseInfo);
        // 保存UserGrowLog相关表
    }

    private User saveUser(Long loginId, String mobile) {
        User user = new User();
        user.setPhone(mobile);
        user.setNickName(mobile);
        user.setCreateTime(new Date().getTime());
        user.setLoginId(loginId);
        // 注册成功+ 激活成功
        long bitState = BitStatesUtils.addState(BitStatesUtils.OP_REGISTED, BitStatesUtils.OP_ACTIVED);
        // 已有状态 + 手机认证
        bitState = BitStatesUtils.addState(bitState, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(bitState);
        // mybatis-plus会自动帮我们返回主键
        insert(user);
        return user;
    }


    private User selectByPhone(String mobile) {
        // Wrapper条件构造器
        Wrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("phone", mobile);
        // 根据条件构造器中的条件，帮助我们查询对应表并设置条件，查询回一条数据
        return selectOne(wrapper);
    }

    private void saveUserBaseInfo(Integer regChannel, Long userId) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setId(userId);
        userBaseInfo.setRegChannel(regChannel);
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfoService.insert(userBaseInfo);
    }

    private void saveUserAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        // @TODO 应该给用户发送一条短信，告知用户支付初始密码
        userAccount.setPassword("123456");
        userAccount.setId(userId);
        userAccount.setCreateTime(new Date().getTime());
        userAccountService.insert(userAccount);
    }
    private Long saveLogin(String password, String mobile) {
        Login login = new Login();
        login.setUsername(mobile);
        login.setPassword(password);
        login.setType(1);
        login.setEnabled(true);
        // 调用uaa服务进行Login保存
        JSONResult jsonResult = uaaFeignService.saveOrUpdate(login);
        // 判断是否保存成功
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobalEnumCode.USER_REGISTER_ERROR);
        Long loginId = Long.valueOf(jsonResult.getData().toString());
        AssertUtil.isNotNull(loginId, GlobalEnumCode.USER_REGISTER_ERROR);
        return loginId;
    }

}
